#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

#include "lwip/init.h"
#include "lwip/timeouts.h"
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
#include "lwip/etharp.h"
#include "lwip/stats.h"
#include "netif/ethernet.h"

/* tapif is provided by lwip-contrib unix port */
#include "netif/tapif.h"
#include "tcp_server.h"
#include "recv.h"

static struct netif g_netif;
static volatile int g_running = 1;
static pthread_t net_thread; 

static void print_banner(void) {
  printf("lwIP NO_SYS + TAP minimal demo\n");
  printf(" - Host TAP : 10.0.0.1/24 (setup by scripts/setup_tap.sh)\n");
  printf(" - lwIP     : 10.0.0.2 (this program)\n");
  printf("Ping it from another terminal: ping 10.0.0.2\n");
  fflush(stdout);
}
static struct tcp_pcb * pcb = NULL;
/* 简单回调：打印连接/收包事件，并回显 */
static void my_on_connect(void *user, struct tcp_pcb *tpcb) {
  LWIP_UNUSED_ARG(user);
  ip_addr_t rip = tpcb->remote_ip;
  
  printf("[tcp] connect %s:%u\n", ipaddr_ntoa(&rip), tpcb->remote_port);
}

static void my_on_recv(void *user, struct tcp_pcb *tpcb, const uint8_t *data, uint16_t len) 
{
  //这里推送到菜单缓存区
  recv_buffer_put_string(data, len);

  LWIP_UNUSED_ARG(user);
  pcb = tpcb; //后续不做回显，拿到pcb可以调用发送发给接收的客户端
  /* 回显收到的数据 */
  // if (len) (void)tcp_server_send(tpcb, data, len);
}

static void my_on_closed(void *user, struct tcp_pcb *tpcb, err_t why) {
  LWIP_UNUSED_ARG(user);
  LWIP_UNUSED_ARG(tpcb);
  printf("[tcp] closed (why=%d)\n", (int)why);
}

static void *net_process() 
{
    while (1) 
    {
        net_run();
    }
    return NULL;
}

uint8_t run_net()
{
    if(pthread_create(&net_thread, NULL, net_process, NULL) != 0)                       //创建调度器线程，成功返回0
    {
        fprintf(stderr, "Failed to create scheduler_thread thread\n");                                  
        return 0;
    }                                                                            
    return 1;
}

int net_run(void) {
  // signal(SIGINT, on_sigint);   /* Ctrl-C for clean exit with stats */
  // signal(SIGTERM, on_sigint);

  print_banner();

  lwip_init();

  ip4_addr_t ipaddr, netmask, gw;
  ip4addr_aton("10.0.0.2", &ipaddr);
  ip4addr_aton("255.255.255.0", &netmask);
  ip4addr_aton("10.0.0.1", &gw);

  if (netif_add(&g_netif, &ipaddr, &netmask, &gw, NULL, tapif_init, ethernet_input) == NULL) {
    fprintf(stderr, "netif_add failed\n");
    return 1;
  }
  netif_set_default(&g_netif);
  netif_set_up(&g_netif);

  /* Start echo demos */
  // httpd_init();      // from lwIP
  // HTTP_API_init(); 

  tcp_server_cfg_t cfg = {
    .port = 1234,
    .on_connect = my_on_connect,
    .on_recv    = my_on_recv,
    .on_closed  = my_on_closed,
    .user       = NULL,
    .disable_nagle = 1,
  };
  if (tcp_server_start(&cfg) != ERR_OK) {
    fprintf(stderr, "tcp_server_start failed\n");
    return 1;
  }

  /* Main poll loop (NO_SYS): drive timers + poll tapif for input */
  while (g_running) 
  {
    /* Process lwIP timeouts (TCP retransmits, ARP aging, etc.) */
    sys_check_timeouts();

    /* Let tapif bring in any received frames without threads.
       tapif_select() blocks briefly and feeds packets to ethernet_input. */
    tapif_select(&g_netif);

    /* If you prefer a fixed period instead of select:
       usleep(50 * 1000);
       tapif_poll(&g_netif);   // if your tapif has poll API
    */
  }
  tcp_server_stop();
#if LWIP_STATS && LWIP_STATS_DISPLAY
  stats_display();
#endif

  printf("Bye\n");
  return 0;
}
